package ee.ut.aa.neuraltic.logic;

import java.util.List;

import org.apache.log4j.Logger;

import ee.ut.aa.neuraltic.genetic.Brain;
import ee.ut.aa.neuraltic.model.Board;
import ee.ut.aa.neuraltic.model.NeuralPlayer;
import ee.ut.aa.neuraltic.model.Player;
import ee.ut.aa.neuraltic.model.RandomPlayer;
import ee.ut.aa.neuraltic.model.TicBoard;
import ee.ut.aa.neuraltic.neural.Network;
import ee.ut.aa.neuraltic.threading.ThreadPool;

public class GeneticTrainer {

	private static Logger log = Logger.getLogger( GeneticTrainer.class );

	//Edit if necessary
	//
	//In case the player makes the first move
	public static int WINVALUE = 10;
	public static int DRAWVALUE = 7;
	public static int LOSSVALUE = -10;
	
	//if player is the second 
	public static int WINVALUE2 = 10;
	public static int DRAWVALUE2 = 7;
	public static int LOSSVALUE2 = -10;
	
	public static int NO_OF_THREADS = 2;

	private static final int RANDOMGAMES = 100;

	Brain brain;
	Competition comp;

	public GeneticTrainer() {

		brain = new Brain();
		brain.initPopulation();
		comp = new Competition();
	}

	public void startTraining( int nrOfIterations ) {

		log.info( "Starting training." );

		int i = 0;
		while( i < nrOfIterations ) {

			int f = 0;

			log.info( "Training iteration=" + i++ );

			log.debug( "Starting brain iteration." );

			brain.iteration();

			List<Network> pop = brain.getPopulation();

			PopulationStats.logNetwork( pop.get( 0 ) );

			log.debug( "Starting training with popluation of size=" + pop.size() );

			//comment out if no threading is required
			
			ThreadPool pool = new ThreadPool(NO_OF_THREADS);
						
			for( Network netOne : pop ) {

				log.debug( "Training network=" + f++ );
				
				//comment out if no threads
				pool.runTask(new CompetitionThread(netOne, pop));
				
				//uncomment following section if no threading is used
				/*
				for( Network netTwo : pop ) {

					//pool.runTask(new CompetitionThread(netOne, netTwo));					
					
					
					NeuralPlayer plOne = new NeuralPlayer( Board.PLAYER_ONE, netOne );
					NeuralPlayer plTwo = new NeuralPlayer( Board.PLAYER_TWO, netTwo );

					Player winner = comp.competition( plOne, plTwo, new TicBoard() );

					if( winner == plOne ) {
						netOne.setValue( netOne.getValue() + WINVALUE );
						netOne.winsOne++;
						netTwo.setValue( netTwo.getValue() + LOSSVALUE );
						netTwo.lossTwo++;
					} else if( winner == plTwo ) {
						netOne.setValue( netOne.getValue() + LOSSVALUE );
						netOne.lossOne++;
						netTwo.setValue( netTwo.getValue() + WINVALUE );
						netTwo.winsTwo++;
					} else {
						netOne.setValue( netOne.getValue() + DRAWVALUE );
						netOne.drwsOne++;
						netTwo.setValue( netTwo.getValue() + DRAWVALUE );
						netTwo.drwsTwo++;
					}
				}
				*/
			}
			
			//comment out if no threading is used
			pool.join();
			log.info( "pool finished" );

			PopulationStats.logStats( pop );

			// If we have debug, then this thing is pointless usually due to
			// huge log amount
			if( !log.isDebugEnabled() ) {

				quicTest( new NeuralPlayer( Board.PLAYER_ONE, pop.get( 0 ) ), new RandomPlayer( Board.PLAYER_TWO ) );
				quicTest( new RandomPlayer( Board.PLAYER_ONE ), new NeuralPlayer( Board.PLAYER_TWO, pop.get( 0 ) ) );
			}
		}
	}

	private void quicTest( Player plOne, Player plTwo ) {

		Logger netlog = Logger.getLogger( "networks" );

		Competition comp = new Competition();

		int wins = 0;
		int drws = 0;
		int loss = 0;

		for( int i = 0; i < RANDOMGAMES; i++ ) {

			Player winner = comp.competition( plOne, plTwo, new TicBoard() );

			if( winner == plOne )
				wins++;
			else if( winner == plTwo )
				loss++;
			else
				drws++;
		}

		String result = "Network result against random player wins=" + wins + ";drws=" + drws + ";loss=" + loss;

		netlog.debug( result );
		log.info( result );
	}
}
